#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <pthread.h>
#include <semaphore.h>
#include <mutex>

// a.:生产和消费
// b.:生产者之间
// c.:消费者之间
template <class T>
class RingQueue
{
public:
    RingQueue(int cap) : _cap(cap), _ring_queue(_cap)
    {
        // 1.对哪个信号量初始化；不需要进程间通信，是0；初始化，是整数，计数器的初始值是多少
        sem_init(&_room_sem, 0, _cap);
        sem_init(&_data_sem, 0, 0);
        // 2.初始化锁
        pthread_mutex_init(&_con_mutex, nullptr);
        pthread_mutex_init(&_pro_mutex, nullptr);
    }

    void P(sem_t &sem)
    {
        // 3.申请信号量，wait
        sem_wait(&sem);
    }

    void V(sem_t &sem)
    {
        // 4.释放信号量，post
        sem_post(&sem);
    }

    void Lock(pthread_mutex_t &mutex)
    {
        pthread_mutex_lock(&mutex);
    }

    void UnLock(pthread_mutex_t &mutex)
    {
        pthread_mutex_unlock(&mutex);
    }

    void Enqueue(const T &in)
    {
        P(_room_sem);
        Lock(_pro_mutex);
        _ring_queue[_pro_index++] = in;
        _pro_index %= _cap;
        UnLock(_pro_mutex);
        V(_data_sem);
    }

    void Pop(T &out)
    {
        P(_data_sem);
        Lock(_con_mutex);
        out = _ring_queue[_con_index++];
        _con_index %= _cap;
        UnLock(_con_mutex);
        V(_room_sem);
    }

    ~RingQueue()
    {
        // 2.对哪个信号量析构，要取地址
        sem_destroy(&_room_sem);
        sem_destroy(&_data_sem);

        pthread_mutex_destroy(&_con_mutex);
        pthread_mutex_destroy(&_pro_mutex);
    }

private:
    // 1.环形队列的信息
    int _cap;
    std::vector<T> _ring_queue;

    // 2.生产和消费的索引
    int _con_index = 0;
    int _pro_index = 0;

    // 3.信号量
    sem_t _room_sem;
    sem_t _data_sem;

    // 4.定义锁，维护多生产之间的关系，多消费者之间的关系
    pthread_mutex_t _con_mutex;
    pthread_mutex_t _pro_mutex;
};